﻿#region Disclaimer/Info
///////////////////////////////////////////////////////////////////////////////////////////////////
// MetaCollection
// 
// MetaCollection is a system to provide a standard structure, permissions and metadata service
// for content organization.
//
// This project is hosted at Google Code at http://code.google.com/p/metacollection/
//
// This project is licensed under the BSD license.  See the License.txt file for more information.
///////////////////////////////////////////////////////////////////////////////////////////////////
#endregion

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text.RegularExpressions;
using System.Xml.Linq;
using MetaCollection.Framework.Helpers;
using System.Globalization;
using MetaCollection.Framework.Configuration;
using System.Configuration;
using MetaCollection.Framework.Model;

namespace MetaCollection.Framework.Validation
{
	/// <summary>
	/// The ItemValidation class provides a 
	/// </summary>
	public class ItemValidation
	{
		/// <summary>
		/// Names of the base Item Properties
		/// </summary>
		internal static readonly string[] BaseNames = { "Id", "ExternalId", "ParentId", "Version", "LeftVersion", "RightVersion",
														"CreatedBy", "Comment", "Name", "Published", "MimeType", "ResourceProvider",
														"Href", "Properties", "Permissions", "Relationships"};
		/// <summary>
		/// Item Model Specification
		/// </summary>
		IItemSpecification m_Spec;

		/// <summary>
		/// Initializes a new instance of the <see cref="ItemValidation"/> class.
		/// </summary>
		/// <remarks>The Item Model Specification includes a listing of all of the properties
		/// and their associated requirements as a list of rules.  These rules are made up of
		/// a field type, an is required flag and a regularexpression</remarks>
		/// <param name="itemSpec">The item model specification.</param>
		public ItemValidation(IItemSpecification itemSpec)
		{
			if (itemSpec == null)
				throw new ArgumentNullException("itemSpec");
			m_Spec = itemSpec;
			ValidateItemSpecification(itemSpec);
		}

		/// <summary>
		/// Validates the item specification is somewhat sane.
		/// </summary>
		/// <param name="itemSpec">The item spec.</param>
		/// <exception cref="ArgumentException">thrown if the rules given in the item specification are not coherent.</exception>
		private static void ValidateItemSpecification(IItemSpecification itemSpec)
		{
			List<string> propNames = new List<string>();
			foreach (IModelProperty prop in itemSpec.Properties)
			{
				// Simple validation to see that the property is not an extended property with the same name as a base property.
				if (prop.IsExtended && BaseNames.Contains(prop.Name))
					throw new ArgumentException(String.Format(CultureInfo.CurrentCulture, "{0} : Cannot define an extended property with the same name as a base property :{1}", itemSpec.Name, prop.Name));
				if (propNames.Contains(prop.Name))
					throw new ArgumentException(String.Format(CultureInfo.CurrentCulture, "{0} : Cannot define a property with the same name. Ensure there is only one specification entry for :{1}", itemSpec.Name, prop.Name));
				if (prop.Validation != null && !string.IsNullOrEmpty(prop.ValidValues))
					foreach (var val in prop.ValidValues.Split(','))
					{
						if (!prop.Validation.IsMatch(val))
							throw new ArgumentException(String.Format(CultureInfo.CurrentCulture, "{0} : Valid Value '{2}' given for {1} does not pass the validation expression given. A value in the valid values collection or validation expression is invalid.", itemSpec.Name, prop.Name, val));
					}
				propNames.Add(prop.Name);
			}
		}

		/// <summary>
		/// Starts a new validation session.
		/// </summary>
		/// <returns>A validation session ready to go with the rules in the ItemValidation set</returns>
		public ValidationSession StartSession()
		{
			ValidationSession session = new ValidationSession(this);

			return session;
		}

		/// <summary>
		/// Gets the item specification.
		/// </summary>
		/// <value>The item specification.</value>
		public IItemSpecification ItemSpecification { get { return m_Spec; } }
	}
}
